In [2]:
import pandas as pd # pandas is a dataframe library
df = pd.read_csv("./data/data-pemilih-kpu.csv", encoding = 'utf-8-sig')
In [109]:
#dimensi dataset terdiri dari 13137 baris dan 2 kolom
df.shape
Out[109]:
In [6]:
#melihat 5 baris pertama dataset
df.head(5)
Out[6]:
In [5]:
#melihat 5 baris terakhir dataset
df.tail(5)
Out[5]:
In [7]:
# mengecek apakah ada data yang berisi null
df.isnull().values.any()
Out[7]:
In [8]:
# mengecek jumlah baris data yang berisi null
len(df[pd.isnull(df).any(axis=1)])
Out[8]:
In [9]:
# menghapus baris null dan recheck kembali
df = df.dropna(how='all')
len(df[pd.isnull(df).any(axis=1)])
Out[9]:
In [10]:
# mengecek dimensi dataset
df.shape
Out[10]:
In [11]:
# mengubah isi kolom jenis kelamin dari text menjadi integer (Laki-laki = 1; Perempuan= 0)
jk_map = {"Laki-Laki" : 1, "Perempuan" : 0}
df["jenis_kelamin"] = df["jenis_kelamin"].map(jk_map)
In [12]:
# cek kembali data apakah telah berubah
df.head(5)
Out[12]:
In [19]:
# Mengecek distribusi jenis kelamin pada dataset
num_obs = len(df)
num_true = len(df.loc[df['jenis_kelamin'] == 1])
num_false = len(df.loc[df['jenis_kelamin'] == 0])
print("Jumlah Pria: {0} ({1:2.2f}%)".format(num_true, (num_true/num_obs) * 100))
print("Jumlah Wanita: {0} ({1:2.2f}%)".format(num_false, (num_false/num_obs) * 100))
In [20]:
from sklearn.model_selection import train_test_split
feature_col_names = ["nama"]
predicted_class_names = ["jenis_kelamin"]
X = df[feature_col_names].values
y = df[predicted_class_names].values
split_test_size = 0.30
text_train, text_test, y_train, y_test = train_test_split(X, y, test_size=split_test_size, stratify=y, random_state=42)
Dataset telah dipecah menjadi 2 bagian, mari kita cek distribusi nya.
In [18]:
print("Dataset Asli Pria : {0} ({1:0.2f}%)".format(len(df.loc[df['jenis_kelamin'] == 1]), (len(df.loc[df['jenis_kelamin'] == 1])/len(df.index)) * 100.0))
print("Dataset Asli Wanita : {0} ({1:0.2f}%)".format(len(df.loc[df['jenis_kelamin'] == 0]), (len(df.loc[df['jenis_kelamin'] == 0])/len(df.index)) * 100.0))
print("")
print("Dataset Training Pria : {0} ({1:0.2f}%)".format(len(y_train[y_train[:] == 1]), (len(y_train[y_train[:] == 1])/len(y_train) * 100.0)))
print("Dataset Training Wanita : {0} ({1:0.2f}%)".format(len(y_train[y_train[:] == 0]), (len(y_train[y_train[:] == 0])/len(y_train) * 100.0)))
print("")
print("Dataset Test Pria : {0} ({1:0.2f}%)".format(len(y_test[y_test[:] == 1]), (len(y_test[y_test[:] == 1])/len(y_test) * 100.0)))
print("Dataset Test Wanita : {0} ({1:0.2f}%)".format(len(y_test[y_test[:] == 0]), (len(y_test[y_test[:] == 0])/len(y_test) * 100.0)))
Terlihat hasilnya, dataset yang telah dipecah dua tetap dapat mempertahankan persentase distribusi jenis kelamin seperti pada dataset asli.
Proses features extraction, berpengaruh terhadap hasil akurasi yang didapatkan nantinya. Disini saya kan menggunakan metode simple yaitu CountVectorizer yang akan membuat matrix frekwensi kemunculan dari suatu karakter di tiap nama yang diberikan, dengan opsi analisa ngram_range 2 - 6 hanya di dalam satu kata saja. Misal Muhammad Irfani Sahnur, menghasilkan n-gram :
In [29]:
from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer(analyzer = 'char_wb', ngram_range=(2,6))
vectorizer.fit(text_train.ravel())
X_train = vectorizer.transform(text_train.ravel())
X_test = vectorizer.transform(text_test.ravel())
In [34]:
from sklearn.linear_model import LogisticRegression
clf = LogisticRegression()
clf.fit(X_train, y_train.ravel())
Out[34]:
Akurasi prediksi menggunakan data test yang didapat cukup lumayan berada pada tingkat 93.6%
In [36]:
# dataset training
print(clf.score(X_train, y_train))
# dataset test
print(clf.score(X_test, y_test))
In [43]:
from sklearn import metrics
clf_predict = clf.predict(X_test)
# training metrics
print("Accuracy: {0:.4f}".format(metrics.accuracy_score(y_test, clf_predict)))
print(metrics.confusion_matrix(y_test, clf_predict, labels=[1, 0]) )
print("")
print("Classification Report")
print(metrics.classification_report(y_test, clf_predict, labels=[1,0]))
In [80]:
jk_label = {1:"Laki-Laki", 0:"Perempuan"}
test_predict = vectorizer.transform(["niky felina"])
res = clf.predict(test_predict)
print(jk_label[int(res)])
Scikit memiliki fitur untuk memudahkan proses diatas dengan mengguanakan Pipeline. Penulisan kode jadi lebih simple dan rapih, berikut konversi kode diatas jika menggunakan Pipeline
In [76]:
from sklearn.pipeline import Pipeline
clf_lg = Pipeline([('vect', CountVectorizer(analyzer = 'char_wb', ngram_range=(2,6))),
('clf', LogisticRegression()),
])
_ = clf_lg.fit(text_train.ravel(), y_train.ravel())
predicted = clf_lg.predict(text_test.ravel())
np.mean(predicted == y_test.ravel())
Out[76]:
Tingkat akurasi persis sama, dan lebih mudah dalam penulisan kode nya. Mari kita lakukan kembali testing prediksi jenis kelamin
In [79]:
result = clf_lg.predict(["muhammad irfani sahnur"])
print(jk_label[result[0]])
Algoritma berikutnya yang akan digunakan adalah Naive Bayes. Lansung saja kita coba
In [83]:
from sklearn.naive_bayes import MultinomialNB
clf_nb = Pipeline([('vect', CountVectorizer(analyzer = 'char_wb', ngram_range=(2,6))),
('clf', MultinomialNB()),
])
clf_nb = clf_nb.fit(text_train.ravel(), y_train.ravel())
predicted = clf_nb.predict(text_test.ravel())
np.mean(predicted == y_test.ravel())
Out[83]:
Dengan algoritman Naive Bayes, tingkat akurasi yang didapatkan sedikit saja lebih rendah dari Logistic Regression yaitu 93.3%. Mari kita lakukan kembali testing prediksi jenis kelamin
In [99]:
result = clf_nb.predict(["Alifah Rahmah"])
print(jk_label[result[0]])
Algoritma terakhir yang akan digunakan adalah Random Forest. Lansung saja kita coba
In [105]:
from sklearn.ensemble import RandomForestClassifier
clf_rf = Pipeline([('vect', CountVectorizer(analyzer = 'char_wb', ngram_range=(2,6))),
('clf', RandomForestClassifier(n_estimators=90, n_jobs=-1)),
])
clf_rf = clf_rf.fit(text_train.ravel(), y_train.ravel())
predicted = clf_rf.predict(text_test.ravel())
np.mean(predicted == y_test.ravel())
Out[105]:
Dengan algoritman Random Forest, tingkat akurasi yang didapatkan lebih rendah dari dua algoritma sebelumnya, itu sebesar 93.12%. Algoritma ini juga mempunyai kekurangan, yaitu performance yang yang lebih lambat. Ok, Mari kita lakukan kembali testing prediksi jenis kelamin
In [108]:
result = clf_rf.predict(["Yuni ahmad"])
print(jk_label[result[0]])
Saya telah membuat implementasi aplikasi prediksi jenis kelamin, silahkan cek di github.